local oo = require("SharedLibs.BaseLib")
local co = require("SharedLibs.CoroLib")
local rb = require("SharedLibs.RBOps")

Debugger = require("SharedLibs.Debugger")

WaitTime = require("SharedLibs.Ops.WaitTime")
Sequence = require("SharedLibs.Ops.Sequence")
Parallel = require("SharedLibs.Ops.Parallel")
LambdaOp = require("SharedLibs.Ops.LambdaOp")
GuardOp = require("SharedLibs.Ops.GuardOp")
Selector = require("SharedLibs.Ops.Selector")
WhileOp = require("SharedLibs.Ops.WhileOp")

WaitSignal = require("SharedLibs.Signal.WaitSignal")

CU = require("SharedLibs.CoUtils")

local m = {}

-- Override + to Sequence % to Parallel and / to OneOf
function OverrideOperator(prototype)
	--- Sequence
	prototype.__add = function (self, another)
		return oo.New(Sequence, self, another);
	end
	--- All of
	prototype.__mod = function (self, another)
		return oo.New(Parallel, self, another);
	end
	--- One Of
	prototype.__div = function (self, another)
		local parallel = oo.New(Parallel, self, another);
		parallel.destCount = 1;

		parallel:SetReturnFilter(
			function(ops)		
				return ops[1]:GetReturn();
			end);
		return parallel;
	end	
end

OverrideOperator(rb.RBTween.prototype);
OverrideOperator(rb.RBWaitEvent.prototype);
OverrideOperator(co.Coroutine.prototype);
OverrideOperator(WaitTime.prototype);
OverrideOperator(Sequence.prototype);
OverrideOperator(Parallel.prototype);
OverrideOperator(LambdaOp.prototype);
OverrideOperator(GuardOp.prototype);
OverrideOperator(Selector.prototype);
OverrideOperator(WhileOp.prototype);
OverrideOperator(GuardOp.prototype);
OverrideOperator(WaitSignal.prototype);

--- 返回值是最先返回的那个Op的返回值
function m.WaitOneOf(...)
	local parallel = oo.New(Parallel, ...);
	parallel.destCount = 1;

	parallel:SetReturnFilter(
		function(ops)
			if ops == nil then
				warn(3333333);
			end
			return ops[1]:GetReturn();
		end);
	
	return co.yield(parallel);
end

--- 返回值是最先返回的那个Op对象
function m.WaitOneOf2(...)
	local parallel = oo.New(Parallel, ...);
	parallel.destCount = 1;

	parallel:SetReturnFilter(
		function(ops)		
			return ops[1];
		end);

	return co.yield(parallel);
end

--- 返回值是最先返回的那个Op对象在Ops列表的索引
function m.WaitOneOf3(...)
	local parallel = oo.New(Parallel, ...);
	parallel.destCount = 1;

	parallel:SetReturnFilter(
		function(ops)		
			return parallel:GetIndex(ops[1]);
		end);

	return co.yield(parallel);
end

m.WaitOneOfr = m.WaitOneOf;
m.WaitOneOfo = m.WaitOneOf2;
m.WaitOneOfi = m.WaitOneOf3;

m.WaitAll = co.Parallel;
m.NewWaitAll = co.NewParallel;


--- 执行一个AsyncOp，直到signal触发或者AsyncOp自行结束
--- 返回值: success, value
--- 	success表示Op是否正常执行完毕了，value是Op或者Signal的返回值
function m.DoUntil(op, signal)
	--local co = co.New(coroFunc);
	local realOp = CU.ToOp(op);
	local waitOp = signal:NewWait();
	local ret = m.WaitOneOf2(realOp, waitOp);
	if ret == op then
		return true, realOp:GetReturn();
	else
		return false, waitOp:GetReturn();
	end
end

--- 和DoUntil类似，区别是打断Op的可以是任意的AsyncOp
function m.DoUntil2(op, interrupterOp)
	--local co = co.New(coroFunc);
	local realOp = CU.ToOp(op);
	local interrupterOp = CU.ToOp(interrupterOp);
	local ret = m.WaitOneOf2(realOp, interrupterOp);
	if ret == op then
		return true, realOp:GetReturn();
	else
		return false, interrupterOp:GetReturn();
	end
end

--- 执行Op，直到Op自行结束或者超时
--- 返回值：如果没超时，则返回Op的返回值，否则返回time
function m.DoWithTimeout(op, time)
	return m.WaitOneOf(CU.ToOp(op), co.NewDelay(time));
end

--- 缩放一个Op的TimeScale. 
--- 本质是设置SWaitTime的Scale. 其它操作都不能Scale
function m.SetOpTimeScale(op, scale)
	if op.isCombinedOp then
		local curOps = op:GetCurOps();
		curOps:ForEach(function(op_)
			m.SetOpTimeScale(op_, scale);
		end)
	else
		op.scale = scale;
	end
end

return m;
